/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.cqcis.uip.base.framework.base;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.cqcis.uip.base.framework.FrameworkConstants;
import com.cqcis.uip.base.framework.UIPTaskException;
import com.cqcis.uip.base.framework.base.adaptor.AbstractRegisteredService;
import com.cqcis.uip.base.framework.common.State;
import com.cqcis.uip.base.framework.common.Task;
import com.cqcis.uip.base.framework.core.RegisteredServiceContext;
import com.cqcis.uip.base.framework.core.Service;
import com.cqcis.uip.base.framework.core.TaskResultProcessor;
import com.cqcis.uip.base.framework.handlers.CommonService;
import com.cqcis.uip.base.framework.utils.LoopThreadPoolExecutor;

/**
 * 通用服务实现, 提供公用的task执行操作(该类上不建议标注任何注解)
 * 
 * @author huangmy
 * @date   2008-6-18
 */
public abstract class AbstractCommonSupport extends AbstractRegisteredService {
	private static Log log = LogFactory.getLog(AbstractCommonSupport.class);
	private LoopThreadPoolExecutor taskExecutor; // 任务执行
	private boolean serviceStarted;
		
	/**
	 * 实现
	 * 
	 * @return
	 */
	protected abstract CommonService getCommonService();
	
	/**
	 * 异步执行task线程数
	 * 
	 * @return
	 */
	protected abstract int getThreadNumberSchedule();
	
	@Override
	public void start(RegisteredServiceContext serviceContext) throws Exception {
		super.start(serviceContext);
		
		this.taskExecutor = LoopThreadPoolExecutor.getExecutor(getThreadNumberSchedule(), getThreadNumberSchedule() * 2, 60, 
				serviceContext.getLogService(), getLogConfiguration(), 
				"Process Tasks " + serviceContext.getRegisteredService().getName(), getIntervalTime());
		
		CommonService cs =  getCommonService();
		if (cs instanceof Service && !this.serviceStarted) {
			((Service)cs).start(serviceContext);
			serviceStarted = true;
		}
		
		for (int i =0; i < getThreadNumberSchedule(); i ++) {
			this.taskExecutor.execute(new Runnable() {
				public void run() {
					scheduleTaskFromQueue(); // schedule
				}
			});
		}		
	}
	
	@Override
	public void stop(RegisteredServiceContext serviceContext) throws Exception {	
		CommonService cs =  getCommonService();
		if (cs instanceof Service) {
			((Service)cs).stop(serviceContext);
			this.serviceStarted = false;
		}
		
		if (this.taskExecutor != null) {
			this.taskExecutor.shutdown();
		}
		
		super.stop(serviceContext);	
	}

	@Override
	protected boolean doSchedule() {		
		return true;
	}
	
	/**
	 * 处理
	 * 
	 */
	private void scheduleTaskFromQueue() {
		Task task = null;
		boolean opened = false;
		while ((task = getTaskQueue().poll()) != null) {
			try {
				task.setState(State.SUCCESS);
				getCommonService().schedule(task);	
				opened = true;
			} catch (Throwable e) {
				opened = false;
				String preMsg = (e instanceof UIPTaskException) ? "" : (FrameworkConstants.TASK_STATE_MSG_INTERFACE_PROCESS_ERROR + ":");
				task.setMessage(preMsg + e.getMessage(), e);
				task.setThrowable(e);
				log.error("Catch Exception in commonService schedule. task: " + task, e);						
			} finally {
				if (!opened) {				
					task.setState(State.ERROR);							
				}	
				
				dispatchTaskResult(task, false);
				doTaskResultRecordForRS(task);
			}
		}
	}

	@Override
	protected boolean doScheduleSync(Task task) {
		boolean s = scheduleFor(task, false); // schedule
		if (!s) {
			return false;
		}
		
		return waitForSyncTaskFinishBlockResult(task);
	}

	@Override
	public boolean processResult(final Task result) {
		final CommonService service = getCommonService();
		if (service instanceof TaskResultProcessor) {
			getExtendProcessResultThreadPoolExecutor().execute(new Runnable() {
				public void run() {					
					try {
					    ((TaskResultProcessor)service).processResult(result);
					} finally {
						afterProcessResult(result);
					}
				}
			});
		} else {
			afterProcessResult(result);
		}
				
		return true;
	}
}
